#include "halley/tools/assets/import_tool.h"
#include "halley/tools/codegen/codegen.h"
#include "halley/tools/project/project.h"
#include "halley/concurrency/task_anchor.h"
#include "halley/tools/assets/check_assets_task.h"
#include <thread>
#include <chrono>
#include "halley/tools/file/filesystem.h"
#include "halley/os/os.h"
#include "halley/game/halley_statics.h"
#include "halley/support/logger.h"
#include "halley/tools/assets/check_source_update_task.h"
#include "halley/tools/project/project_loader.h"

using namespace Halley;
using namespace std::chrono_literals;

namespace {
	enum class CurArgType {
		Manifest,
		DisabledPlatforms
	};
}

int ImportTool::run(Vector<std::string> args)
{
	if (args.size() >= 2) {
		const Path projectPath = FileSystem::getAbsolute(Path(args[0]));
		const Path halleyRootPath = FileSystem::getAbsolute(Path(args[1]));
		Logger::logInfo("Importing project at \"" + projectPath + "\", with Halley root at \"" + halleyRootPath);

		std::optional<Path> manifestPath;
		Vector<String> disabledPlatforms;

		CurArgType curArgType = CurArgType::Manifest;
		for (size_t i = 2; i < args.size(); ++i) {
			const auto arg = String(args[i]);

			if (arg.startsWith("--")) {
				if (arg == "--disabled-platforms") {
					curArgType = CurArgType::DisabledPlatforms;
				}
			} else if (curArgType == CurArgType::Manifest) {
				manifestPath = FileSystem::getAbsolute(Path(arg));
			} else if (curArgType == CurArgType::DisabledPlatforms) {
				disabledPlatforms += arg;
			}
		}

		ProjectLoader loader(*statics, halleyRootPath, disabledPlatforms);
		auto proj = loader.loadProject(projectPath);
		Logger::logInfo("Project loaded.");

		if (manifestPath) {
			proj->setAssetPackManifest(*manifestPath);
		}
		Logger::logInfo("Using manifest at \"" + proj->getAssetPackManifestPath() + "\"");

		auto tasks = std::make_unique<TaskSet>();
		tasks->setListener(*this);
		tasks->addTask(std::make_unique<CheckAssetsTask>(*proj, true));
		tasks->addTask(std::make_unique<CheckSourceUpdateTask>(*proj, false, true));
		auto last = std::chrono::steady_clock::now();
		Logger::logInfo("Waiting on tasks...");

		while (!tasks->getTasks().empty()) {
			std::this_thread::sleep_for(50ms);

			auto now = std::chrono::steady_clock::now();
			float elapsed = std::chrono::duration<float>(now - last).count();
			last = now;

			tasks->update(elapsed);
		}

		if (hasError) {
			Logger::logError("Import failed.");
			return 1;
		} else {
			Logger::logInfo("Import done.");
			return 0;
		}
	} else {
		Logger::logError("Usage: halley-cmd import projDir halleyDir");
		return 1;
	}
}

void ImportTool::onTaskAdded(const std::shared_ptr<TaskAnchor>& task)
{
	Logger::logInfo("Task added: " + task->getName());
}

void ImportTool::onTaskTerminated(const std::shared_ptr<TaskAnchor>& task)
{
	Logger::logInfo("Task ended: " + task->getName());
}

void ImportTool::onTaskError(const std::shared_ptr<TaskAnchor>& task)
{
	Logger::logError("Task ended in error: " + task->getName());
	hasError = true;
}
